import tornado.httpserver
import tornado.ioloop
import tornado.options
from tornado.web import RequestHandler
from tornado.options import define, options
import time
import datetime
import os
import py_eureka_client.eureka_client as eureka_client
from logHandler import getLogger
import common as com
from tornado import gen
from tornado.concurrent import run_on_executor
from concurrent.futures import ThreadPoolExecutor

define("eurekaServer", default="http://192.168.1.133:8761/eureka/", help="eureka服务器地址", type=str)
define("appName", default="python-multithreading", help="注册应用名称", type=str)
define("port", default=8003, help="程序端口号", type=int)

class InfoHandler(RequestHandler):
    executor = ThreadPoolExecutor(max_workers=5)

    @gen.coroutine
    def get(self):
        log = getLogger()
        i = yield self.background_task()
        log.info("hello python eureka!")
        self.write("hello python eureka!")

    @run_on_executor
    def background_task(self):
        return "2"


class NonBlockingHandler(RequestHandler):
    executor = ThreadPoolExecutor(max_workers=5)

    @gen.coroutine
    def get(self):
        log = getLogger()
        i = yield self.background_task(log)
        self.write("睡眠结束!")

    @run_on_executor
    def background_task(self,log):
        log.info("开始睡眠20秒")
        time.sleep(20)
        log.info("睡眠20秒结束")
        return "20"

class TimeoutTest(RequestHandler):
    executor = ThreadPoolExecutor(max_workers=5)

    @gen.coroutine
    def get(self):
        log = getLogger()
        try:
            # 能捕获到异常，但是background_task还会继续执行，没有跳过：输出为 1.开始睡眠20秒 2.超时捕获成功 3.睡眠20秒结束；主线程是结束了，但子线程如果卡死了，就一直占用着资源也释放不了
            # 但是这个问题可以从业务层解决，应该也不会有线程一直卡死
            yield gen.with_timeout(datetime.timedelta(seconds=5), [self.background_task(log)], quiet_exceptions = gen.TimeoutError)
        except gen.TimeoutError:
            log.error("超时捕获成功")

    @run_on_executor
    def background_task(self, log):
        log.info("开始睡眠20秒")
        time.sleep(20)
        log.info("睡眠20秒结束")

def eurekaClient():
    # 判断日志目录是否存在，不存在则创建
    log_path = com.logPath
    if os.path.exists(log_path) is False:
        os.makedirs(log_path)

    tornado.options.parse_command_line()
    log = getLogger()
    log.info("eureka开始启动")
    eureka_client.init_registry_client(eureka_server=options.eurekaServer,
                                       app_name=options.appName,
                                       instance_port=options.port)
    log.info("eureka启动成功")
    app = tornado.web.Application(
        handlers=[
            (r"/info", InfoHandler),
            (r"/nonBlockingHandler", NonBlockingHandler),
            (r"/timeoutTest", TimeoutTest)
        ],
    )
    http_server = tornado.httpserver.HTTPServer(app)
    http_server.listen(options.port)
    tornado.ioloop.IOLoop.instance().start()

if __name__ == "__main__":
    eurekaClient()